#include "Dictionary.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <algorithm>
#include <iterator>

//静态单例对象的初始化
unique_ptr<Dictionary> Dictionary::instance = nullptr;
once_flag Dictionary::initDictionaryFlag;

Dictionary::Dictionary(){

}

Dictionary::~Dictionary(){

}

//获取静态单例对象
Dictionary* Dictionary::createInstance(){
    call_once(initDictionaryFlag, &Dictionary::initInstance);
    return instance.get();
}

void Dictionary::initInstance(){
    instance.reset(new Dictionary());
}

//初始化字典
void Dictionary::init(const string &dictpath) {
    //确保只初始化一次
    if(_dict.size()){
        return;
    }

    ifstream ifs1(dictpath + "/dict_cn.dat");
    ifstream ifs2(dictpath + "/index_cn.dat");
    ifstream ifs3(dictpath + "/dict_en.dat");
    ifstream ifs4(dictpath + "/index_en.dat");
    
    string line, key, value;
    //读中文词典
    while(ifs1 >> key && ifs1 >> value){
        _dict.push_back({key, stoi(value)});
    }
    //读中文词典索引表
    while(getline(ifs2, line)){
        istringstream iss(line);
        iss >> key;
        while(iss >> value){
            _indexTable[key].insert(stoi(value));
        }
    }
    //读英文词典
    while(ifs3 >> key && ifs3 >> value){
        _dictEn.push_back({key, stoi(value)});
    }
    //读英文词典索引表
    while(getline(ifs4, line)){
        istringstream iss(line);
        iss >> key;
        while(iss >> value){
            _indexTableEn[key].insert(stoi(value));
        }
    }

    /* cout << _dict.size() << endl; */
    /* cout << _indexTable.size() << endl; */
    /* cout << _dictEn.size() << endl; */
    /* cout << _indexTableEn.size() << endl; */
    
    cout << "初始化词典和词典的索引表成功\n";
}

//获取中文字典
vector<pair<string, int>>& Dictionary::getDict(){
    return _dict;
}

//获取中文字典索引表
map<string, set<int>>& Dictionary::getIndexTable(){
    return _indexTable;
}

//获取英文字典
vector<pair<string, int>> &Dictionary::getDictEn(){
    return _dictEn;
}

//获取英文字典索引表
map<string, set<int>> &Dictionary::getIndexTableEn(){
    return _indexTableEn;
}

//获取要读取的字节
static size_t nBytesCode(const char ch){
    if(ch & (1 << 7)){
        int nBytes = 1;
        for(int idx = 0; idx != 6; ++idx){
            if(ch & (1 << (6 - idx))){
                ++nBytes;
            }   
            else{
                break;
            }   
        }   
        return nBytes;
    }   
    return 1;
}

//执行查询
string Dictionary::doQuery(string word) {
    set<int> setUnion;
    for(size_t i = 0; i < word.size();){
        size_t size = nBytesCode(word[i]);
        string s = word.substr(i, size);
        /* cout << s << endl; */
        i += size;
        set_union(setUnion.begin(), setUnion.end(), _indexTable[s].begin(), _indexTable[s].end(), inserter(setUnion, setUnion.begin()));
    }
    
    string result; 
    for(auto &i: setUnion){
        result += _dict[i].first + " ";
    }
    
    return result;
}
